﻿using System;
using System.Text;
using System.Data;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using IntraVision.Web;
using IntraVision.Web.Security;
using Model;

/// <summary>
/// Summary description for ProductionReportController
/// </summary>
[AllowedRole("Finance", "ProductionReport")]
public class ProductionReportController : ReportController<NotarialServiceDataContext>
{
    #region NotarialActionInfo class
    private class NotarialActionInfo
    {
        #region Fields
        private int _bestTime, _ordersCount, _seconds, _count;
        private List<decimal> _marks;
        #endregion

        #region .ctor
        public NotarialActionInfo(int id, string name, int position)
        {
            Id = id;
            Name = name;
            Position = position;

            _bestTime = _ordersCount = _seconds = _count = 0;

            _marks = new List<decimal>();
        }
        #endregion

        #region Methods
        public void AddInfo(int seconds, int ordersCount, decimal mark)
        {
            _marks.Add(mark);
            _ordersCount += ordersCount;
            AddSeconds(seconds);
            ++_count;
        }

        public void AddSeconds(int seconds)
        {
            if (seconds > 0 && (_bestTime == 0 || _bestTime > seconds))
                _bestTime = seconds;

            _seconds += seconds;
        }

        public void Reset()
        {
            _seconds = 0;
            _count = 0;
            _marks.Clear();

            return;
        }
        #endregion

        #region Properties
        public int Id { get; set; }

        public string Name { get; set; }

        public int Position { get; set; }

        public int Count { get { return _count; } }

        public string FormattedName
        {
            get { return string.Format("<a id=\"n{0}\" href=\"#\">{1}</a>", this.Id, this.Name); }
        }

        public int AvgTime
        {
            get { return ((_count > 0) ? Convert.ToInt32(_seconds / _count) : 0); }       
        }

        public decimal AvgMark
        {
            get { return ((_marks.Count > 0) ? _marks.Average() : 0); }
        }

        public int OrdersCount
        {
            get { return _ordersCount; }
        }

        public int BestTime
        {
            get { return _bestTime; }
        }
        #endregion
    }
    #endregion

    DateTime _StartDate;
    DateTime _EndDate;
    string _SortOrder;

    public ProductionReportController(): base()
    {
        _isCalculateTotal = false;

        //_StartDate = _EndDate = DateTime.Now;
        _StartDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
        _EndDate = new DateTime(DateTime.Now.Year, DateTime.Now.AddMonths(1).Month, 1).AddDays(-1);
    }

    public override void Default()
    {
        InitDatesFromRequest();

        ViewData["months"] = GetMonthList();
        ViewData["years"] = GetYearsList(DateTime.Now.Year, 10);

        base.Default();
    }

    protected override void InitParams(NotarialServiceDataContext dc)
    {
        //подкорректируем диапазон дат, чтобы учесть крайние границы времени
        _StartDate = _StartDate.AddHours(-_StartDate.Hour);
        _StartDate = _StartDate.AddMinutes(-_StartDate.Minute);
        _EndDate = _EndDate.AddHours(-_EndDate.Hour + 23);
        _EndDate = _EndDate.AddMinutes(-_EndDate.Minute + 59);

        _CommandParams.Clear();
        _CommandParams.Add("@StartDate", _StartDate);
        _CommandParams.Add("@EndDate", _EndDate); 
    }

    private void InitDatesFromRequest()
    {
        DateTime bufDateTime;

        if (!String.IsNullOrEmpty(Request["startdate"]) && DateTime.TryParse(Request["startdate"], out bufDateTime))
        {
            _StartDate = bufDateTime;
            ViewData["currentYear"] = _StartDate.Year;
            ViewData["currentMonth"] = _StartDate.Month;
        }

        if (!String.IsNullOrEmpty(Request["enddate"]) && DateTime.TryParse(Request["enddate"], out bufDateTime))
            _EndDate = bufDateTime;

        if (!String.IsNullOrEmpty(Request["sortorder"]))
            _SortOrder = Request["sortorder"];
    }

    protected override void DataReceived(DataSet ds)
    {
        base.DataReceived(ds);

        ViewData["startdate"] = _StartDate;
        ViewData["enddate"] = _EndDate;
        ViewData["sortorder"] = _SortOrder; 
    }

    protected override void PrepareDataTable(ref DataTable dt)
    {
        var resultTable = new DataTable();
        var actionInfoList = new List<NotarialActionInfo>();
        int position, actionId, seconds, ordersCount;
        decimal avgMark;
        DataRow bufRow;
        string userIdStr;
        NotarialActionInfo actionInfo;

        CreateColumns(dt, ref resultTable);
        
        //заполняем ячеки итоговой таблицы
        foreach(DataRow dr in dt.Rows)
        {
            position = resultTable.Rows.Count;
            actionId = Convert.ToInt32(dr["NotarialActionId"]);
            userIdStr = string.Format("u{0}",Convert.ToString(dr["UserId"]));
            actionInfo = actionInfoList.FirstOrDefault(na => na.Id == actionId);

            if (actionInfo != null)
                position = actionInfo.Position;
            else
            {
                actionInfo = new NotarialActionInfo(actionId, Convert.ToString(dr["BreadCrumbs"]), position);
                actionInfoList.Add(actionInfo);
                bufRow = resultTable.NewRow();
                bufRow["action"] = actionInfo.FormattedName;
                resultTable.Rows.Add(bufRow);
            }

            seconds = Convert.ToInt32(dr["Seconds"]);
            ordersCount = Convert.ToInt32(dr["OrdersCount"]);
            avgMark = Convert.ToDecimal(dr["AvgMark"]);

            actionInfo.AddInfo(seconds, ordersCount, avgMark);  
            resultTable.Rows[position][userIdStr] = string.Format("{0}<br/>({1}/{2})", FormatSeconds(seconds), ordersCount, avgMark.FormatNumber());
        }

        //заполняем столбцы лучшего и среднего времени
        foreach (var ai in actionInfoList)
        {
            bufRow = resultTable.Rows[ai.Position];

            bufRow["avg"] = string.Format("{0}<br/>({1}/{2})", FormatSeconds(ai.AvgTime), ai.OrdersCount, ai.AvgMark.FormatNumber());
            bufRow["best"] = FormatSeconds(ai.BestTime);
        }

        //заполняем ячейки с пустыми значениями
        foreach (DataRow dr in resultTable.Rows)
            foreach (DataColumn dc in resultTable.Columns)
                if (string.IsNullOrEmpty(dr[dc.ColumnName].ToString()))
                    dr[dc.ColumnName] = "0 сек<br/>(0/0)";
               
        dt = resultTable;       

        return;
    }

    protected void CreateColumns(DataTable sourceTable, ref DataTable resultTable)
    {
        string additionalCaption = "<br/>(число документов /<br/>средняя оценка)";
        int actionId;

        //первый столбец со списком нотариальных действий
        DataColumn c = resultTable.Columns.Add("action");
        c.Caption = string.Format("{0} /<br/> {1}", _StartDate.ToShortDateString(), _EndDate.ToShortDateString());

        //если задан порядок сортировки, то сначала создадим столбцы для пользователей с операциями для выбранного нот. действия
        if (!string.IsNullOrEmpty(_SortOrder) && Int32.TryParse(_SortOrder.TrimStart('n'), out actionId))
        {
            DataRow[] foundRows = sourceTable.Select(string.Format("NotarialActionId = {0}", actionId), "Seconds ASC, UserName ASC");
            foreach (var row in foundRows)
                AddUserColumn(ref resultTable, row, additionalCaption);
        }
       
        foreach (DataRow dr in sourceTable.Rows)
            AddUserColumn(ref resultTable, dr, additionalCaption);

        //столбцы для среднего и лучшего времен
        c = resultTable.Columns.Add("avg");
        c.Caption = string.Format("Среднее время {0}", additionalCaption);
        c = resultTable.Columns.Add("best");
        c.Caption = string.Format("Лучшее время");
    }

    protected void AddUserColumn(ref DataTable dt, DataRow sourceRow, string additionalCaption)
    {
        string columnId = "u" + sourceRow["UserId"];

        if (!dt.Columns.Contains(columnId))
        {
            var c = dt.Columns.Add(columnId);
            c.Caption = Convert.ToString(string.Format("{0} {1}", sourceRow["UserName"], additionalCaption));
        }
    }

    private string FormatSeconds(int seconds)
    {
        var sb = new StringBuilder();

        var ts = new TimeSpan(0, 0, seconds);

        if (ts.Hours > 0)
            sb.AppendFormat("{0} ч ", ts.Hours.ToString());

        if (ts.Hours > 0 || ts.Minutes > 0)
            sb.AppendFormat("{0} мин ", ts.Minutes.ToString());

        sb.AppendFormat("{0} сек ", ts.Seconds.ToString());

        return sb.ToString();
    }
}
